<template>
  <div>
    <section v-show="!data || !data.fileName">
      <section class="upload-form">
        <input type="file" name="file" id="fileUpload" @change="ApiUploadBigFile" />
        <span v-show="uploading">
          上传中
          <a-icon type="loading" />
        </span>
      </section>
      <a-progress :percent="percent" :status="percent != 100 ? 'active' : 'success'" />
    </section>
    <section v-show="data && data.fileName">
      <a-tag closable @close="handlerCloseTag">{{ data ? data.fileName : "" }}</a-tag>
    </section>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Emit, Vue } from "vue-property-decorator";
import axios from "axios";
import { PREFIX } from "@/api/cfg";
import { SleepSync } from "@/utils";

@Component({ name: "UploadTemp" })
export default class UploadTemp extends Vue {
  @Prop({ type: Object }) data: any;
  private percent: number = 0;
  private uploading: boolean = false;
  private isCancel: boolean = false;

  @Emit("done")
  uploadDone(info: any): any {
    return info;
  }

  @Emit("uploading")
  uploadStatus(status: boolean) {
    this.uploading = status;
    return status;
  }

  percentClean() {
    this.percent = 0;
  }

  initTemp() {
    const fileInp: any = document.getElementById("fileUpload");
    fileInp.value = "";
    this.isCancel = false;
  }

  @Emit("remove")
  handlerCloseTag() {}

  async ApiUploadBigFile() {
    this.percentClean();
    const objFile: any = document.getElementById("fileUpload");
    const file = objFile.files[0];
    const bytesPerPiece = 20 << 20; //切片大小 20M
    let start = 0;
    let end;
    let index: any = 0;
    const file_size: number = file.size;
    const file_name: string = file.name;
    const totalPieces: any = Math.ceil(file_size / bytesPerPiece);
    const timestamp: any = new Date().getTime();
    while (start < file_size && !this.isCancel) {
      this.uploadStatus(true);
      end = start + bytesPerPiece;
      if (end > file_size) {
        end = file_size;
      }
      const chunk = file.slice(start, end); //执行切片操作
      const sliceName = file_name + "." + index;
      const originalName = file_name;
      const formData: any = new FormData();
      formData.append("timestamp", timestamp);
      formData.append("fileName", originalName);
      formData.append("name", sliceName);
      formData.append("size", file_size);
      formData.append("total", totalPieces);
      formData.append("index", index);
      formData.append("file", chunk);
      const { data } = await axios.post(`${PREFIX}/driver`, formData, {
        headers: {
          "Content-Type": "application/x- www-form-urlencoded"
        }
      });
      if (data?.errNo == 0) {
        this.percent = Math.ceil(((index + 1) / totalPieces) * 100);
        start = end;
        index++;
      } else {
        Promise.reject("文件传输过程中服务器发生错误");
        return;
      }
    }
    this.uploadStatus(false);
    if (!this.isCancel)
      await this.mergeChunk(totalPieces, file_name, file_size);
  }

  async mergeChunk(
    total: number,
    fname: string,
    fsize: number,
    scaler: number = 1
  ) {
    const maxNum: number = 15;
    try {
      const { data } = await axios.post(`${PREFIX}/driver/merge`, {
        total,
        fname,
        fsize
      });
      if (data.errNo == 0) {
        const { resNo } = data.item;
        if (resNo) {
          this.uploadDone(data.item);
        } else {
          if (scaler < maxNum) {
            await SleepSync(500);
            await this.mergeChunk(total, fname, fsize, ++scaler);
          }
        }
      }
    } catch (error) {
      return null;
    }
  }
}
</script>

<style lang="less" scoped>
.upload-form {
  display: flex;
  span {
    color: #40a9ff;
  }
}
</style>
